﻿using Simhopp.Common;
using System;
using System.ComponentModel;
using System.Windows;

namespace Simhopp.Client
{
  
    
    public partial class Presenter : IPresenterBindings, INotifyPropertyChanged
    {
        private Competition _competition;
        private ListOfCompetitions _competitions;
        /// <summary>
        /// The currently active judge
        /// </summary>
        public User ActiveJudge { get; set; }
        private readonly ServerListener _serverListener;
        
        /// <summary>
        /// Constructor for the presenter. 
        /// </summary>
        public Presenter() : base()
        {
            /*
             * Initalisera alla collections och alla data strukturer
             */
            Competition = new Competition();
            ActiveJudge = new User();
            nowJumpingData = new NowJumpingDataStruct(new Diver(), Rounds.Configure);
            _serverListener = new ServerListener(this);
            _competitions = new ListOfCompetitions();

        }

        /// <summary>
        /// Handles an incoming network data object. Discards anything that is not a NetworkCommand.
        /// </summary>
        /// <param name="obj">The network command as an object</param>
        public void ProcessObject(Object obj)
        {
            if ((obj as NetworkCommand) == null)
                return;

            var commandPackage = obj as NetworkCommand;
            switch (commandPackage.Command)
            {
                case Commands.ScoreReceived:
                    ProcessScoreReceived(commandPackage.Obj as String);
                    break;
                case Commands.AddVerifiedScore:
                    ProcessAddVerifiedScore(commandPackage.Obj as Score);
                    break;
                case Commands.Competition:
                    ProcessCompetitionReceived(commandPackage.Obj as Competition);
                    break;
                case Commands.NextRound:
                    ProcessNextRound();
                    break;
                case Commands.NextDiver:
                    ProcessNextDiver();
                    break;
                case Commands.LoginVerified:
                    ProcessLoginVerified(commandPackage.Obj as User);
                    break;
                case Commands.LoginFailed:
                    ProcessLoginFailed(commandPackage);
                    break;
                case Commands.AllCompetitions:
                    ProcessAllCompetitions(commandPackage.Obj as ListOfCompetitions);
                    break;
            }
        }

        /// <summary>
        /// Handles the Commands.AllCompetitions command and its data.
        /// </summary>
        /// <param name="competitions">The competitionlist</param>
        private void ProcessAllCompetitions(ListOfCompetitions competitions)
        {
            _competitions = competitions;
            NotifyPropertyChanged(propertyName: "Competitions");
        }
        /// <summary>
        /// Handles the NextRound NetworkCommand.
        /// </summary>
        private void ProcessNextRound()
        {
            App.Current.Dispatcher.Invoke((Action)delegate
            {
                Competition.NextRound();
            });
            ScoreVerification = "";
            NotifyPropertyChanged(String.Empty);
            NowJumpingData = new NowJumpingDataStruct(Competition.GetCurrentDiver(), Competition.CurrentRound);
        }

        /// <summary>
        /// Handles the NextDiver NetworkCommand.
        /// </summary>
        private void ProcessNextDiver()
        {
            App.Current.Dispatcher.Invoke((Action)delegate
            {
                Competition.NextDiver();
            });
            ScoreVerification = "";
            NotifyPropertyChanged(String.Empty);
            NowJumpingData = new NowJumpingDataStruct(Competition.GetCurrentDiver(), Competition.CurrentRound);
        }

        /// <summary>
        /// Handles the LoginFailed NetworkCommand.
        /// </summary>
        /// <param name="command">The network command</param>
        private void ProcessLoginFailed(NetworkCommand command)
        {
            if((command.Obj as String) == null)
                MessageBox.Show(String.Format("Du kunde ej loggas in."));
            else
            {
                var additionalText = command.Obj as String;
                MessageBox.Show(String.Format(String.Format("Du kunde ej loggas in - {0}", additionalText)));
            }
        }
        /// <summary>
        /// Handles the LoginVerified NetworkCommand.
        /// </summary>
        /// <param name="user">The userdata for the login.</param>
        public void ProcessLoginVerified(User user)
        {
            ActiveJudge = user;
            NotifyPropertyChanged(propertyName: "AdministratorViewVisibilityState");
            NotifyPropertyChanged(propertyName: "JudgeViewVisibilityState");
            NotifyPropertyChanged(propertyName: "HeadJudgeViewVisibilityState");
            NotifyPropertyChanged(propertyName: "UserInfo");
        }

        /// <summary>
        /// Handles the Competition NetworkCommand
        /// </summary>
        /// <param name="competition">The competition that was received.</param>
        private void ProcessCompetitionReceived(Competition competition)
        {
            Competition = ( (competition != null) ? competition : new Competition() );
            ScoreVerification = "";
            competition.JudgesOnly = null;
            NotifyPropertyChanged(propertyName: "JudgesOnly");
            NotifyPropertyChanged(propertyName: "AccessLevelJudge");
            NotifyPropertyChanged(propertyName: "AccessLevelHeadJudge");
            if (competition.CurrentRound != Rounds.Configure)
            {
                NowJumpingData = new NowJumpingDataStruct(competition.GetCurrentDiver(), competition.CurrentRound);
            }
            NotifyPropertyChanged(propertyName: String.Empty);
        }

        /// <summary>
        /// Handles the AddVerifiedScore command. 
        /// </summary>
        /// <param name="score">The score object.</param>
        private void ProcessAddVerifiedScore(Score score)
        {
            var indexOfCurrentRound = Competition.GetIndexOfCurrentRound();
            Competition.GetCurrentDiver().AddScoreToDive(indexOfCurrentRound, score);
            if (Competition.GetCurrentDiver().NoOfScoresSet(indexOfCurrentRound) == Competition.NumberOfJudges)
            {
                Competition.GetCurrentDiver().UpdateTotalScore(indexOfCurrentRound);
                NotifyPropertyChanged(propertyName: "TotalScore");
            }
        }

        /// <summary>
        /// Handles verification of own score.
        /// </summary>
        /// <param name="verification">The string to show</param>
        private void ProcessScoreReceived(String verification)
        {
            ScoreVerification = verification;
        }

        /// <summary>
        /// Handles graceful shutdown of client and sockets to prevent memory leaks and runaway threads.
        /// </summary>
        public void ExitGraceful()
        {
            _serverListener.Stop();
        }
    }
}
